/*
 * i8259.c
 *
 *  Created on: 2016-10-1
 *      Author: m
 */
#include "string.h"
#include "type.h"
#include "global.h"
#include "sub.h"

/* 8259A interrupt controller ports. */
#define INT_M_CTL   0x20    /* I/O port for interrupt controller         <Master> */
#define INT_M_CTLMASK   0x21    /* setting bits in this port disables ints   <Master> */
#define INT_S_CTL   0xA0    /* I/O port for second interrupt controller  <Slave>  */
#define INT_S_CTLMASK   0xA1    /* setting bits in this port disables ints   <Slave>  */

/* 中断向量 */
#define INT_VECTOR_IRQ0         0x20
#define INT_VECTOR_IRQ8         0x28
/*
                       |<- IRQ0-Clock           |IRQ8-RealTimeClock
  cpu <-- master-8259A |<- IRQ1-Key             |IRQ9-RedirectionIRQ2
                       |<------------8295 slave-|IRQ10-Preserve
                       |<- IRQ3-Uart2           |IRQ11-Preserve
                       |<- IRQ4-Uart1           |IRQ12-Mouse
                       |<- IRQ5-LPT2            |IRQ13-FPU Error
                       |<- IRQ6-Floppy          |IRQ14-AT温盘
                       |<- IRQ7-LPT1            |IRQ15-Preserve


顺序不可颠倒
往端口0x20(主片)或0xA0(从片)写入ICW1
往端口0x21(主片)或0xA1(从片)写入ICW2
往端口0x21(主片)或0xA1(从片)写入ICW3
往端口0x21(主片)或0xA1(从片)写入ICW4
 ICW1-ICW4:初始化命令字,在对8259A用初始化命令字进行初始化后，就进入工作状态
ICW1 对应端口0x20 0xa0, 无论何时，当A0=0(偶地址)并且D4=1时，都被认为是ICW1
             _特征位D4，必须为1
            |    _1:level triggered模式 0：edge triggered模式
            |   |    _1:4字节中断向量 0：8字节中断向量
            |   |   |    _1：单个8259, 0：级联8259
            |   |   |   |    _1:需要ICW4, 0:不需要ICW4
_fixed:0_  _|_ _|_ _|_ _|_ _|_
 7  6  5    4   3   2   1   0

ICW2 对应端口0x21 0xa1
        _80x86中断向量
       |            _000:80x86系统
 ______|______ ____|___
 7  6  5  4  3  2  1  0

主片ICW3 对应端口0x21
bitX 1:IRX级联从片 0：无从片
                              _1:IR0级联从片 0：无从片
_|_ _|_ _|_ _|_ _|_ _|_ _|_ _|_
 7   6   5   4   3   2   1   0

从片ICW3 对应端口0xa1
                          _从片连的主片的IR号
_____fixed:0______  _____|____
 7   6   5   4   3   2   1   0

ICW4 对应端口0x21 0xa1
              _1：SFNM模式 0：sequential模式
             |      _主/从缓冲模式
             |     |      _自动EOI 0：正常EOI
             |     |     |    _1:80x86模式 0：MCS 80/85
__no-use__  _|_ ___|___ _|_ _|_
 7   6   5   4   3   2   1   0

OCW1 对应端口0x21和0xa1
  X: 0:IRQX打开， 1：关闭
                       _0:IRQ0打开， 1：关闭
                     _|_
 7  6  5  4  3  2  1  0

 OCW2 对应端口0x21和0xa1
         _当每一次中断处理结束，需要发送一个EOI给8295以便继续接收中断
        |
 R  SL EOI  0  0  L2 L1 L0
 7  6   5   4  3  2  1  0
D7 D6  D5  D4 D3 D2 D1 D0

三条OCW命令次序上没有要求(实际上还有一个OCW3未列出)
OCW1写入奇地址端口
OCW2、OCW3写入偶地址端口
  D3=D4=0时为OCW2
  D3=1 D4=0时为OCW3
*/
void init_8259A() {
    out_byte(INT_M_CTL, 0x11);/* Master 8259, ICW1. */
    out_byte(INT_S_CTL, 0x11);/* Slave  8259, ICW1. */
    out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0);/* Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20. */
    out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8);/* Slave  8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28 */
    out_byte(INT_M_CTLMASK, 0x4);/* Master 8259, ICW3. IR2 对应 '从8259'. */
    out_byte(INT_S_CTLMASK, 0x2);/* Slave  8259, ICW3. 对应 '主8259' 的 IR2. */
    out_byte(INT_M_CTLMASK, 0x1);/* Master 8259, ICW4. */
    out_byte(INT_S_CTLMASK, 0x1);/* Slave  8259, ICW4. */

    out_byte(INT_M_CTLMASK, 0xFF);/* 奇地址:OCW1 Master 8259. Clock Interrupt disable */
    out_byte(INT_S_CTLMASK, 0xFF);/* Slave  8259, OCW1.  */
}

void hw_int_proc(int int_no) {
    printf("interrupt happen, int_no=%d\n", int_no);
}

void set_irq_handler(int irq_no, irq_handler handler) {
    disable_irq(irq_no);
    g_irq_table[irq_no] = handler;
}
